/*
 * @Author: shenghao.xu
 * @Date: 2023-04-24 21:33:46
 * @LastEditors: shenghao.xu
 * @LastEditTime: 2023-04-24 23:09:57
 * @Description:
 * email:545403892@qq.com
 * Copyright (c) 2023 by shenghao.xu, All Rights Reserved.
 */
#include "flash.h"

static BOOL flash_erase(uint32_t addr, uint16_t nb)
{
    if (HAL_FLASH_Unlock() != HAL_OK)
        return FALSE;
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
    FLASH_WaitForLastOperation(10); // 等待一下，提升擦除成功率

    uint32_t PageError = 0;
    FLASH_EraseInitTypeDef Eras;
    Eras.NbPages = nb;
    Eras.PageAddress = addr;
    Eras.TypeErase = FLASH_TYPEERASE_PAGES;

    if (HAL_FLASHEx_Erase(&Eras, &PageError) != HAL_OK)
    {
        HAL_FLASH_Lock();
        return FALSE;
    }

    if (HAL_FLASH_Lock() != HAL_OK)
    {
        HAL_FLASH_Lock();
        return FALSE;
    }

    return TRUE;
}

/**
 * This function reads a specified number of bytes from a given address in flash memory and stores them
 * in a buffer.
 *
 * @param addr The starting address from where the bytes will be read from the flash memory.
 * @param buf A pointer to a buffer where the read data will be stored.
 * @param size The number of bytes to be read from the flash memory starting from the specified
 * address.
 *
 * @return a BOOLean value (either TRUE or FALSE) depending on whether the size parameter is equal to
 * zero or not.
 */
BOOL flash_read_byte(uint32_t addr, uint8_t *buf, uint32_t size)
{
    if (size == 0)
        return FALSE;

    uint32_t read_num = 0;
    uint32_t read_addr = addr;
    while (read_num < size)
    {
        *(buf + read_num) = *(__IO uint8_t *)read_addr++;
        read_num++;
    }
    return TRUE;
}

/**
 * The function writes data to flash memory without using a buffer.
 *
 * @param addr The starting address in flash memory where the data will be written.
 * @param buf A pointer to the buffer containing the data to be written to flash memory.
 * @param size The size of the data to be written in bytes.
 *
 * @return a BOOLean value (either TRUE or FALSE) depending on whether the flash write operation was
 * successful or not.
 */
BOOL flash_write_no_buffer(uint32_t addr, uint32_t *buf, uint32_t size)
{
    uint32_t i;
    uint32_t read_data;
    if (size == 0)
        return FALSE;

    if (!flash_erase(addr, (size + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE))
    {
        return FALSE;
    }

    if (HAL_FLASH_Unlock() != HAL_OK)
    {
        return FALSE;
    }

    for (i = 0; i < size; i += 4, buf++, addr += 4)
    {
        /* write data */
        HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr, (uint32_t)*buf);

        read_data = *(uint32_t *)addr;
        /* check data */
        if (read_data != *buf)
        {
            HAL_FLASH_Lock();
            return FALSE;
        }
    }

    if (HAL_FLASH_Lock() != HAL_OK)
        return FALSE;

    return TRUE;
}
